/*
    DrawGraphics.cpp

    Date:
        05-09-10

    Descripton:
        A collection of functions to display vector graphics
        using OpenGL methods. These are used by object classes
        to display their data.

    Authors:
        Nathaniel Brown
        Subodh Prabhu
        Jesus Suarez
*/


/****************************************************************************/
/*                              I N C L U D E S                             */
/****************************************************************************/

#include <cmath>
#include "GlutHeaders.h"
#include "DrawGraphics.h"
#include "Item.h"
#include "Theme.h"

/****************************************************************************/
/*                               E X T E R N S                              */
/****************************************************************************/

extern int currentWindowHeight;
extern int currentWindowWidth;
extern Theme thm;

/****************************************************************************/
/*                     U T I L I T Y   F U N C T I O N S                    */
/****************************************************************************/

double timeToDeg(double time) {
  double degrees = 30.0 * (3.0 - time);
  if(degrees < 0)
    return degrees + 360;
  else
    return degrees;
}

double timeToRad(double time) {
  double radians = PI * (3.0 - time) / 6.0;
  if(radians < 0)
    return radians + 2 * PI;
  else
    return radians;
}

bool get_arc_rads(int level, double &inner_rad, double &outer_rad) {
  switch(level) {
    case APPOINTMENT:
      inner_rad = CLOCK_RAD * APPOINTMENT_IN;
      outer_rad = CLOCK_RAD * APPOINTMENT_OUT;
      break;
    case TASK:
      inner_rad = CLOCK_RAD * TASK_IN;
      outer_rad = CLOCK_RAD * TASK_OUT;
      break;
    case FUN_TIME:
      inner_rad = CLOCK_RAD * FUN_TIME_IN;
      outer_rad = CLOCK_RAD * FUN_TIME_OUT;
      break;
    case EVENT:
      inner_rad = CLOCK_RAD * EVENT_IN;
      outer_rad = CLOCK_RAD * EVENT_OUT;
      break;
    default:
      return false;
  }
  return true;
}

/****************************************************************************/
/*                    G R A P H I C S   F U N C T I O N S                   */
/****************************************************************************/

void drawDisk() {
  float theta = 2 * PI / 50.0;
  float tangetial_factor = tanf(theta);   // calculate the tangential factor
  float radial_factor = cosf(theta);      // calculate the radial factor	
  float x = CLOCK_RAD;                    // radial vector
  float y = 0;

  glBegin(GL_POLYGON);
  for(int ii = 0; ii < 50; ii++) {
    glVertex2f(x + currentWindowWidth / 2,
               y + currentWindowHeight / 2);  // output vertex

    float tx = -y;		                    // calculate the tangential vector
    float ty = x;

    x += tx * tangetial_factor;           //add the tangential vector
    y += ty * tangetial_factor;

    x *= radial_factor;                   //correct using the radial factor
    y *= radial_factor;
  }
  glEnd();
}

void drawCircle() {
  float theta = 2 * PI / 50.0;
  float tangetial_factor = tanf(theta);   // calculate the tangential factor
  float radial_factor = cosf(theta);      // calculate the radial factor	
  float x = CLOCK_RAD;                    // radial vector
  float y = 0;

  glLineWidth(CLOCK_BORDER_W);
  glBegin(GL_LINE_LOOP);
  for(int ii = 0; ii < 50; ii++) {
    glVertex2f(x + currentWindowWidth / 2,
               y + currentWindowHeight / 2);  // output vertex

    float tx = -y;		                    // calculate the tangential vector
    float ty = x;

    x += tx * tangetial_factor;           //add the tangential vector
    y += ty * tangetial_factor;

    x *= radial_factor;                   //correct using the radial factor
    y *= radial_factor;
  }
  glEnd();
}

void drawArc(int level, double start_time, double end_time) {
  double inner_rad, outer_rad;
  if(!get_arc_rads(level, inner_rad, outer_rad))
    return;

  double end = timeToRad(start_time);       // convert to
  double start = timeToRad(end_time);       // counter-clockwise convention
  if(end < start) end += 2 * PI;
  
  glPushMatrix();
  glTranslated(currentWindowWidth / 2, currentWindowHeight / 2, 0);
  glPointSize(3.0);
  double angle1 = start, angle2 = start + FIVEDEGREES;
  for(; angle2 < end; angle1 += FIVEDEGREES, angle2 += FIVEDEGREES) {    
    glBegin(GL_POLYGON);
    glVertex2d(inner_rad * cos(angle1), -inner_rad * sin(angle1));
    glVertex2d(inner_rad * cos(angle2), -inner_rad * sin(angle2));
    glVertex2d(outer_rad * cos(angle2), -outer_rad * sin(angle2));
    glVertex2d(outer_rad * cos(angle1), -outer_rad * sin(angle1));
    glEnd();
  }
  glBegin(GL_POLYGON);
  glVertex2d(inner_rad * cos(angle1), -inner_rad * sin(angle1));
  glVertex2d(inner_rad * cos(end), -inner_rad * sin(end));
  glVertex2d(outer_rad * cos(end), -outer_rad * sin(end));
  glVertex2d(outer_rad * cos(angle1), -outer_rad * sin(angle1));
  glEnd();
  glPopMatrix();
}

void drawTick(double time) {
  glPushMatrix();
  glTranslated(currentWindowWidth / 2, currentWindowHeight / 2, 0);
  glRotatef(timeToDeg(time), 0.0, 0.0, -1.0);
  glLineWidth(CLOCK_TICK_W);
  glLineWidth(1);
  glColor4f(thm.hourLineColor.r, thm.hourLineColor.g, thm.hourLineColor.b, thm.hourLineColor.t);
  glBegin(GL_LINES);
    glVertex2d(0.0, 0.0);
    glVertex2d(CLOCK_RAD, 0.0);
  glEnd();
  glColor4f(thm.tickColor.r, thm.tickColor.g, thm.tickColor.b, thm.tickColor.t);
  glLineWidth(4);
  glBegin(GL_LINES);
    glVertex2d(CLOCK_RAD - 2 * CLOCK_TICK_L / 3, 0.0);
    glVertex2d(CLOCK_RAD + CLOCK_TICK_L / 3, 0.0);
  glEnd();
  glPopMatrix();
}

void drawNode(double time) {
  drawArc(EVENT, time - 0.06, time + 0.06);
}

void drawLine(double time) {
  glPushMatrix();
  glTranslated(currentWindowWidth / 2, currentWindowHeight / 2, 0);
  glRotatef(timeToDeg(time), 0.0, 0.0, -1.0);
  glLineWidth(CLOCK_TICK_W);
  glBegin(GL_LINES);
    glVertex2d(0.0, 0.0);
    glVertex2d(CLOCK_RAD, 0.0);
  glEnd();
  glPopMatrix();
}
